﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using ClearingRestartingAutomaton.Base;

namespace ClearingRestartingAutomaton.Common
{
    /// <summary>
    /// Static class encapsulating default string patterns.
    /// </summary>
    public static class RegexPatterns
    {
        /// <summary>
        /// Get the word pattern.
        /// </summary>
        public static string WordPattern
        {
            get
            {
                return RegexPatterns.wordPattern;
            }
        }

        /// <summary>
        /// Get the left context pattern.
        /// </summary>
        public static string LeftContextPattern
        {
            get
            {
                return RegexPatterns.leftContextPattern;
            }
        }

        /// <summary>
        /// Get the right context pattern.
        /// </summary>
        public static string RightContextPattern
        {
            get
            {
                return RegexPatterns.rightContextPattern;
            }
        }

        /// <summary>
        /// Get the regex pattern for clearing instructions.
        /// </summary>
        public static string ClearingInstructionPattern
        {
            get
            {
                return RegexPatterns.clearingInstructionPattern;
            }
        }

        /// <summary>
        /// Get the regex pattern for reducing instructions.
        /// </summary>
        public static string ReducingInstructionPattern
        {
            get
            {
                return RegexPatterns.reducingInstructionPattern;
            }
        }

        /// <summary>
        /// Get the regex pattern for generating instructions.
        /// </summary>
        public static string GeneratingInstructionPattern
        {
            get
            {
                return RegexPatterns.generatingInstructionPattern;
            }
        }

        /// <summary>
        /// Get Regex instance for word.
        /// </summary>
        public static Regex WordRegex
        {
            get
            {
                return RegexPatterns.wordRegex;
            }
        }

        /// <summary>
        /// Get Regex instance for left context.
        /// </summary>
        public static Regex LeftContextRegex
        {
            get
            {
                return RegexPatterns.leftContextRegex;
            }
        }

        /// <summary>
        /// Get Regex instance for right context.
        /// </summary>
        public static Regex RightContextRegex
        {
            get
            {
                return RegexPatterns.rightContextRegex;
            }
        }

        /// <summary>
        /// Get the Regex instance for clearing instructions.
        /// </summary>
        public static Regex ClearingInstructionRegex
        {
            get
            {
                return RegexPatterns.clearingInstructionRegex;
            }
        }

        /// <summary>
        /// Get the Regex instance for reducing instructions.
        /// </summary>
        public static Regex ReducingInstructionRegex
        {
            get
            {
                return RegexPatterns.reducingInstructionRegex;
            }
        }

        /// <summary>
        /// Get the Regex instance for generating instructions.
        /// </summary>
        public static Regex GeneratingInstructionRegex
        {
            get
            {
                return RegexPatterns.generatingInstructionRegex;
            }
        }

        /// <summary>
        /// Parses the instructions from the given string.
        /// </summary>
        /// <param name="line">String representation of the instruction.</param>
        /// <returns>Array of instructions.</returns>
        public static Instruction[] ParseInstructions(string line)
        {
            if (String.IsNullOrWhiteSpace(line))
            {
                return null;
            }

            line = line.Trim();

            string left = null;
            string right = null;
            string from = null;
            string to = null;
            bool matched = false;

            Match clearingMatch = RegexPatterns.ClearingInstructionRegex.Match(line);
            Match reducingMatch = RegexPatterns.ReducingInstructionRegex.Match(line);
            Match generatingMatch = RegexPatterns.GeneratingInstructionRegex.Match(line);

            if (clearingMatch.Success && clearingMatch.Length > 0)
            {
                left = clearingMatch.Groups["left"].ToString();
                right = clearingMatch.Groups["right"].ToString();
                from = clearingMatch.Groups["from"].ToString();
                to = "";
                matched = true;
            }
            else if (reducingMatch.Success && reducingMatch.Length > 0)
            {
                left = reducingMatch.Groups["left"].ToString();
                right = reducingMatch.Groups["right"].ToString();
                from = reducingMatch.Groups["from"].ToString();
                to = reducingMatch.Groups["to"].ToString();
                matched = true;
            }
            else if (generatingMatch.Success && generatingMatch.Length > 0)
            {
                left = generatingMatch.Groups["left"].ToString();
                right = generatingMatch.Groups["right"].ToString();
                from = generatingMatch.Groups["from"].ToString();
                to = generatingMatch.Groups["to"].ToString();
                matched = true;
            }

            if (matched)
            {
                from = from.Replace(".", "").Trim();
                to = to.Replace(".", "").Trim();

                char[] separators = { ' ', '\t', '\r', '\n', ',', ';' };
                string[] leftSet = left.Split(separators, StringSplitOptions.RemoveEmptyEntries);
                string[] rightSet = right.Split(separators, StringSplitOptions.RemoveEmptyEntries);
                
                if (leftSet.Length == 0) leftSet = new string[] { "" };
                if (rightSet.Length == 0) rightSet = new string[] { "" };

                List<Instruction> instructionList = new List<Instruction>(leftSet.Length * rightSet.Length);
                for (int li = 0; li < leftSet.Length; ++li)
                {
                    for (int ri = 0; ri < rightSet.Length; ++ri)
                    {
                        string leftContext = leftSet[li].Replace(".", "").Trim();
                        string rightContext = rightSet[ri].Replace(".", "").Trim();
                        instructionList.Add(new Instruction(leftContext, from, to, rightContext));
                    }
                }

                return instructionList.ToArray();
            }

            return null;
        }

        private static readonly string wordPattern = @"^[a-zA-Z0-9!@#%&\*\(\)\'\\/_\+\:""\|\?.]*$";

        private static readonly string leftContextPattern = @"^\^?[a-zA-Z0-9!@#%&\*\(\)\'\\/_\+\:""\|\?.]*$";

        private static readonly string rightContextPattern = @"^[a-zA-Z0-9!@#%&\*\(\)\'\\/_\+\:""\|\?.]*\$?$";

        private static readonly string clearingInstructionPattern =
            @"^\s*\[(?<left>\s*(\^?[a-zA-Z0-9!@#%&\*\(\)\'\\/_\+\:""\|\?.,;]*\s*)*)\]\s*" +
            @"(?<from>[a-zA-Z0-9!@#%&\*\(\)\'\\/_\+\:""\|\?.]+)" +
            @"\s*\[(?<right>\s*([a-zA-Z0-9!@#%&\*\(\)\'\\/_\+\:""\|\?.,;]*\$?\s*)*)\]\s*$";

        private static readonly string reducingInstructionPattern =
            @"^\s*\[(?<left>\s*(\^?[a-zA-Z0-9!@#%&\*\(\)\'\\/_\+\:""\|\?.,;]*\s*)*)\]\s*" +
            @"(?<from>[a-zA-Z0-9!@#%&\*\(\)\'\\/_\+\:""\|\?.]+)" +
            @"\s*->\s*(?<to>[a-zA-Z0-9!@#%&\*\(\)\'\\/_\+\:""\|\?.]+)" +
            @"\s*\[(?<right>\s*([a-zA-Z0-9!@#%&\*\(\)\'\\/_\+\:""\|\?.,;]*\$?\s*)*)\]\s*$";

        private static readonly string generatingInstructionPattern =
            @"^\s*\[(?<left>\s*(\^?[a-zA-Z0-9!@#%&\*\(\)\'\\/_\+\:""\|\?.,;]*\s*)*)\]\s*" +
            @"(?<to>[a-zA-Z0-9!@#%&\*\(\)\'\\/_\+\:""\|\?.]+)" +
            @"\s*->\s*(?<from>[a-zA-Z0-9!@#%&\*\(\)\'\\/_\+\:""\|\?.]+)" +
            @"\s*\[(?<right>\s*([a-zA-Z0-9!@#%&\*\(\)\'\\/_\+\:""\|\?.,;]*\$?\s*)*)\]\s*$";

        private static readonly Regex wordRegex = new Regex(wordPattern);
        private static readonly Regex leftContextRegex = new Regex(leftContextPattern);
        private static readonly Regex rightContextRegex = new Regex(rightContextPattern);
        private static readonly Regex clearingInstructionRegex = new Regex(clearingInstructionPattern);
        private static readonly Regex reducingInstructionRegex = new Regex(reducingInstructionPattern);
        private static readonly Regex generatingInstructionRegex = new Regex(generatingInstructionPattern);
    }
}
